package com.lime49.lockcrypt;
import com.lime49.lockcrypt.ui.IconTableModel;
import com.lime49.lockcrypt.ui.AbstractDialog;
import com.lime49.lockcrypt.ui.GradientJPanel;
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.table.*;
import javax.swing.border.*;
import java.util.*;
import java.net.URL;

/**
* Used to add/edit accounts.
*/
public class FrmAddAccount extends AbstractDialog implements ILanguageParent {
    private ResourceBundle lang;
    private ILanguageParent owner;
    private Account account;
    private JPanel content, buttonBox;
    private GridBagConstraints c;
    private JScrollPane scrollContainer;
    
    private JTextField txtAccName;
    private JComboBox cAccGroup, cAccType;
    private JTextArea txtNotes;
    private HashMap<String,int[]> iconMap;
    private JTable iconTable;
    private LinkedHashMap<String, JTextField> fieldMap;
    private LinkedHashMap<String, String> hiddenMap;
    private AccType tempType;
    private boolean editing;
    
    private AccountTree accountTree;
    public ArrayList<AccType> types;
    public ArrayList<Group> groups;
    
    public FrmAddAccount(ILanguageParent owner, Account origaccount, boolean editing, ResourceBundle lang, AccountTree accountTree, ArrayList<AccType> types, ArrayList<Group> groups) {
        super(owner.getParentWindow() instanceof JFrame ? (JFrame)owner.getParentWindow() : null, true);
        this.owner = owner;
        this.account = (Account)origaccount.clone();
        this.editing = editing;
        this.lang = lang;
        this.accountTree = accountTree;
        this.types = types;
        this.groups = groups;
        KeyStroke escapeKeyStroke = KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE, 0, false);
        Action escapeAction = new AbstractAction() {
            // cancel the dialog when the user presses escape
            public void actionPerformed(ActionEvent e) {
                dispose();
            }
        }; 
        this.getRootPane().getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(escapeKeyStroke, "ESCAPE");
        this.getRootPane().getActionMap().put("ESCAPE", escapeAction);
        
        content = new JPanel(new GridBagLayout());
        content.setBorder(Constants.EMPTYBORDER);
        scrollContainer = new JScrollPane(content, JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED, JScrollPane.HORIZONTAL_SCROLLBAR_NEVER);
            scrollContainer.setBorder(null);
            this.setContentPane(scrollContainer);
        c = new GridBagConstraints();
            c.insets = Constants.GLOBALINSETS;
        
        Utils.setgrid(c,0,0,1,1,GridBagConstraints.NONE,GridBagConstraints.NORTHWEST,0.5);
        JLabel lblaccname = new JLabel(lang.getString("NAME")+":");
            content.add(lblaccname,c);
        txtAccName = new JTextField(12);
            lblaccname.setLabelFor(txtAccName);
            txtAccName.setText(account.getName());
        Utils.setgrid(c,0,1,GridBagConstraints.REMAINDER,1,GridBagConstraints.HORIZONTAL,GridBagConstraints.NORTHWEST,1);
            content.add(txtAccName,c);
        Utils.setgrid(c,1,0,1,1,GridBagConstraints.NONE,GridBagConstraints.NORTHWEST,0.5);
        JLabel lblaccgroup = new JLabel(lang.getString("GROUP")+":");
            content.add(lblaccgroup,c);
        cAccGroup = new JComboBox();
            lblaccgroup.setLabelFor(cAccGroup);
            cAccGroup.addItem("LockCrypt");
            for(Group group : groups) {
                if(!group.getIsDeleted()) {
                    cAccGroup.addItem(group.getName());
                }
            }
            cAccGroup.setSelectedItem(account.getGroup());
        Utils.setgrid(c,1,1,GridBagConstraints.REMAINDER,1,GridBagConstraints.HORIZONTAL,GridBagConstraints.NORTHWEST,1);
            content.add(cAccGroup,c);
        Utils.setgrid(c,2,0,1,1,GridBagConstraints.NONE,GridBagConstraints.NORTHWEST,0.5);
        JLabel lblacctype = new JLabel(lang.getString("TYPE")+":");
            content.add(lblacctype,c);
        cAccType = new JComboBox();
            lblacctype.setLabelFor(cAccType);
            for(AccType opt : types) {
                if(!opt.isDeleted) {
                    cAccType.addItem(opt.getName());
                }
            }
            if(editing) {
                this.setTitle(lang.getString("EDITACCOUNT"));
            } else {
                if(cAccType.getItemCount() == 0) {
                    JOptionPane.showMessageDialog(this,lang.getString("ERR_NOTYPESFOUND_DESC"),lang.getString("ERR_NOTYPESFOUND"), JOptionPane.ERROR_MESSAGE);
                    return;
                } else {
                    this.setTitle(lang.getString("ADDACCOUNT"));
                    try {
                        account.setType(types.get(Utils.getTypeIndex("Blank", types, "list")));
                    } catch(Exception e) {
                        account.setType(types.get(0));
                    }
                }
            }
            boolean foundIndex = false;
            for(int i=0;i<cAccType.getItemCount();i++) {
                if(cAccType.getItemAt(i).toString().equals(account.getType())) {
                    foundIndex = true;
                    cAccType.setSelectedIndex(i);
                    break;
                }
            }
            if(!foundIndex) {
                // if the type has since been deleted, recraeet it for the list
                tempType = account.getTypeObject();
                cAccType.addItem(tempType.getName());
                cAccType.setSelectedIndex(cAccType.getItemCount()-1);
            }
        Utils.setgrid(c,2,1,GridBagConstraints.REMAINDER,1,GridBagConstraints.HORIZONTAL,GridBagConstraints.NORTHWEST,1);
            content.add(cAccType,c);
            cAccType.addItemListener(new AccTypeChoiceListener());
            
        buttonBox = new JPanel();
            buttonBox.setLayout(new BoxLayout(buttonBox, BoxLayout.LINE_AXIS));
            JButton btnOk = new JButton();
            JButton btnCancel = new JButton(lang.getString("CANCEL"));
            btnOk.addActionListener(new ActionListener() {
                public void actionPerformed(ActionEvent e) {
                    if(validateAccount()) {
                        result = JOptionPane.OK_OPTION;
                        dispose();
                    }
                }
            });
            if(editing) {
                btnOk.setActionCommand("edit");
                btnOk.setText(lang.getString("SAVE"));
            } else {
                btnOk.setActionCommand("add");
                btnOk.setText(lang.getString("ADD"));
            }
            btnCancel.addActionListener(new ActionListener() {
               public void actionPerformed(ActionEvent e) {
                   dispose();
               }
            });
            JButton btnConfigureAutotype = new JButton(lang.getString("CONFIGAUTOTYPE"));
            btnConfigureAutotype.addActionListener(new ActionListener() {
                public void actionPerformed(ActionEvent e) {
                    configureAutoType();
                }
            });
            try {
                ImageIcon icoName = new ImageIcon();
                URL URLicon = this.getClass().getResource("images/autotype_16.png");
                icoName.setImage(Toolkit.getDefaultToolkit().getImage(URLicon));
                btnConfigureAutotype.setIcon(icoName);
            } catch(Exception e) { }
            buttonBox.add(btnConfigureAutotype);
            buttonBox.add(Box.createHorizontalGlue());
            buttonBox.add(btnOk);
            buttonBox.add(Box.createHorizontalStrut(10));
            buttonBox.add(btnCancel);
            btnOk.setMinimumSize(Constants.MINSIZE);
            btnOk.setPreferredSize(Constants.PREFSIZE);
            btnOk.setMaximumSize(Constants.MAXSIZE);
            btnConfigureAutotype.setMinimumSize(new Dimension(Constants.MINSIZE.width*2, Constants.MINSIZE.height));
            btnConfigureAutotype.setPreferredSize(new Dimension(Constants.PREFSIZE.width*2, Constants.PREFSIZE.height));
            btnConfigureAutotype.setMaximumSize(new Dimension(Constants.MAXSIZE.width*2, Constants.MAXSIZE.height));
            btnCancel.setMinimumSize(Constants.MINSIZE);
            btnCancel.setPreferredSize(Constants.PREFSIZE);
            btnCancel.setMaximumSize(Constants.MAXSIZE);
        this.getRootPane().setDefaultButton(btnOk);
        
        iconTable = iconBox();
        fieldMap = new LinkedHashMap<String,JTextField>();
        hiddenMap = new LinkedHashMap<String,String>();

        this.setMinimumSize((new Dimension(490,400)));
        this.setPreferredSize((new Dimension(520,450)));
        this.setLocationRelativeTo(owner.getParentWindow());
        getTextFields();
        this.setVisible(true);
    }
    
    /**
     * Shows the field names for the currently selected account type by
     * reading the name from <i>selectedAccount</i>. Also selects the icon for
     * the current account and adds Ok and Cancel buttons to the dialog.
     */
    private void getTextFields() {
        int cury = c.gridy+1;
        int componentCount = content.getComponentCount();
        for(int i=componentCount-1; i>=6;i--) {
            content.remove(content.getComponent(i));
        }
        c.weighty = 0;
        fieldMap.clear();
        hiddenMap.clear();
        JTextField curfield;
        JComboBox curlabel;
        HashMap<String, JComboBox> labelmap = new HashMap<String, JComboBox>();
        LinkedHashMap<String, String> fields = account.getTypeObject().getFieldMap();
        for(final String fieldname : fields.keySet()) {
            Utils.setgrid(c,cury,0,1,1,GridBagConstraints.HORIZONTAL,GridBagConstraints.NORTHWEST,0.5);
            boolean obfuscated = false,
                    phoneNumber = false,
                    url = false;
            String prettyName;
            if(fieldname.startsWith("~}")) {
                switch(fieldname.charAt(2)) {
                    case '*': // obfuscated field
                        prettyName = fieldname.substring(3);
                        obfuscated = true;
                        break;
                    case '#': // phone number
                        prettyName = fieldname.substring(3);
                        phoneNumber = true;
                        break;
                    case '!':
                        prettyName = fieldname.substring(3);
                        if(owner.getDebug()) {
                            break;
                        } else {
                            hiddenMap.put(fieldname, account.getField(fieldname));
                            continue;
                        }
                    case 'u':
                        prettyName = fieldname.substring(3);
                        url = true;
                        break;
                    default:
                        prettyName = fieldname;
                        break;
                }
            } else {
                prettyName = fieldname;
            }
            String[] comboOptions = {
                prettyName, 
                lang.getString("RENAMEFIELD"), 
                lang.getString("DELFIELD"),
                lang.getString("MARKASPASSWORD"),
                lang.getString("PHONENUMBER"),
                lang.getString("MARKASURL")
            };
            curlabel = new JComboBox(comboOptions);
                curlabel.setSelectedIndex(0);
                labelmap.put(fieldname, curlabel);
                curlabel.addActionListener(new ActionListener() {
                   public void actionPerformed(ActionEvent e) {
                       JComboBox src = (JComboBox)e.getSource();
                       String itm = (String)src.getSelectedItem();
                       if(itm.equals(lang.getString("RENAMEFIELD"))) {
                           src.setSelectedIndex(0);
                           showAddFieldDialog((String)src.getItemAt(0), true);
                       } else if(itm.equals(lang.getString("DELFIELD"))) {
                           LinkedHashMap<String, String> fields = account.getTypeObject().getFieldMap();
                            for(String fieldname : fields.keySet()) {
                                account.setField(fieldname, ((JTextField)fieldMap.get(fieldname)).getText());
                            }
                           account.removeField((String)src.getItemAt(0));
                           getTextFields();
                       } else if(itm.equals(lang.getString("MARKASPASSWORD"))) {
                           LinkedHashMap<String, String> fields = account.getTypeObject().getFieldMap();
                            for(String fieldname : fields.keySet()) {
                                account.setField(fieldname, ((JTextField)fieldMap.get(fieldname)).getText());
                            }
                           account.obfuscateField((String)src.getItemAt(0));
                           getTextFields();
                       } else if(itm.equals(lang.getString("PHONENUMBER"))) {
                           LinkedHashMap<String, String> fields = account.getTypeObject().getFieldMap();
                            for(String fieldname : fields.keySet()) {
                                account.setField(fieldname, ((JTextField)fieldMap.get(fieldname)).getText());
                            }
                           account.togglePhoneNumber((String)src.getItemAt(0));
                           getTextFields();
                       } else if(itm.equals(lang.getString("MARKASURL"))) {
                           LinkedHashMap<String, String> fields = account.getTypeObject().getFieldMap();
                            for(String fieldname : fields.keySet()) {
                                account.setField(fieldname, ((JTextField)fieldMap.get(fieldname)).getText());
                            }
                           account.toggleUrlField((String)src.getItemAt(0));
                           getTextFields();
                       }
                   }
                });
            content.add(curlabel,c);
            
            curfield = null;
            if(obfuscated) {
                Box pnlPassword = Box.createHorizontalBox();
                    Utils.setgrid(c,cury,1,GridBagConstraints.REMAINDER,1,GridBagConstraints.HORIZONTAL,GridBagConstraints.NORTHEAST,1);
                    content.add(pnlPassword,c);
                    cury++;
                curfield = new JTextField(22);
                    curfield.setBackground(Color.getHSBColor(0F,0.32F,1F));
                    curfield.setText(account.getField(fieldname));
                    fieldMap.put(fieldname,curfield);
                    pnlPassword.add(fieldMap.get(fieldname));
                
                pnlPassword.add(Box.createHorizontalStrut(5));

                JButton btnGenerate = new JButton("");
                    btnGenerate.setHorizontalAlignment(SwingConstants.LEFT);
                    btnGenerate.setToolTipText(lang.getString("PWGEN_GENERATE"));
                    try {
                        ImageIcon icoName = new ImageIcon();
                        URL URLicon = this.getClass().getResource("images/password_16.png");
                        icoName.setImage(Toolkit.getDefaultToolkit().getImage(URLicon));
                        btnGenerate.setIcon(icoName);
                    } catch(Exception ignore) { }
                    pnlPassword.add(btnGenerate);
                    
                    final GradientJPanel pnlPasswordStrength = new GradientJPanel(new BorderLayout());
                        Utils.setgrid(c,cury,1,GridBagConstraints.REMAINDER,1,GridBagConstraints.HORIZONTAL,GridBagConstraints.NORTHEAST,1);
                        content.add(pnlPasswordStrength,c);
                        cury++;
                        pnlPasswordStrength.setBorder(BorderFactory.createLineBorder(Color.black));
                        
                        int pwStrength = PWStrengthChecker.checkStrength((curfield).getText());

                        final JLabel lblPWMeter = new JLabel(pwStrength+"% - "+PWStrengthChecker.getStrengthDescription(pwStrength, lang)),
                                     lblBitStrength = new JLabel(PWStrengthChecker.calculateBitStrength(curfield.getText())+" bits");
                        PWStrengthChecker.setPanelGradient(pnlPasswordStrength, pwStrength);
                        pnlPasswordStrength.add(lblPWMeter, BorderLayout.LINE_START);
                        pnlPasswordStrength.add(lblBitStrength, BorderLayout.LINE_END);
                          
                        curfield.addKeyListener(new KeyListener() {
                            public void keyTyped(KeyEvent e) { }
                            public void keyPressed(KeyEvent e) { }
                            public void keyReleased(KeyEvent e) {
                                String pw = ((JTextField)e.getSource()).getText();
                                int pwStrength = PWStrengthChecker.checkStrength(pw);
                                lblPWMeter.setText(pwStrength+"% - "+PWStrengthChecker.getStrengthDescription(pwStrength, lang));
                                PWStrengthChecker.setPanelGradient(pnlPasswordStrength, pwStrength);
                                lblBitStrength.setText(PWStrengthChecker.calculateBitStrength(pw)+" bits");
                            }
                        });
                    
                    btnGenerate.addActionListener(new ActionListener() {
                        public void actionPerformed(ActionEvent e) {
                            FrmPWGen frmPWGen = new FrmPWGen(thisDialog, lang);
                                Point parentLoc = thisDialog.getLocation();
                                frmPWGen.setLocation(parentLoc.x + ((thisDialog.getWidth() - frmPWGen.getWidth())/2), parentLoc.y + ((thisDialog.getHeight() - frmPWGen.getHeight())/2));
                                frmPWGen.setVisible(true);
                            String selectedPassword = frmPWGen.getSelectedPassword();
                            if(selectedPassword.length() > 0) {
                                fieldMap.get(fieldname).setText(selectedPassword);
                                int pwStrength = PWStrengthChecker.checkStrength(selectedPassword);
                                lblPWMeter.setText(pwStrength+"% - "+PWStrengthChecker.getStrengthDescription(pwStrength, lang));
                                PWStrengthChecker.setPanelGradient(pnlPasswordStrength, pwStrength);
                                lblBitStrength.setText(PWStrengthChecker.calculateBitStrength(selectedPassword)+" bits");   
                            }
                        }
                    });
            } else {
                if(phoneNumber) {
                    curfield = new JTextField(22) {
                        @Override
                        protected void paintComponent(Graphics g) {
                            super.paintComponent(g);
                            try {
                                URL url = this.getClass().getResource("images/phone.png");
                                final java.awt.image.BufferedImage image = javax.imageio.ImageIO.read(url);
                                Border border = UIManager.getBorder("TextField.border");
                                JTextField defaultField = new JTextField();
                                final int x0 = getWidth() - border.getBorderInsets(defaultField).right - image.getWidth();
                                setMargin(new Insets(2, 2, 2, getWidth() - x0));
                                int y = (getHeight() - image.getHeight())/2;
                                g.drawImage(image, x0, y, this);
                            } catch(Exception ignore) {}
                        }
                    };
                } else if(url) {
                    curfield = new JTextField(22) {
                        @Override
                        protected void paintComponent(Graphics g) {
                            super.paintComponent(g);
                            try {
                                URL url = this.getClass().getResource("images/language_16.png");
                                final java.awt.image.BufferedImage image = javax.imageio.ImageIO.read(url);
                                Border border = UIManager.getBorder("TextField.border");
                                JTextField defaultField = new JTextField();
                                final int x0 = getWidth() - border.getBorderInsets(defaultField).right - image.getWidth();
                                setMargin(new Insets(2, 2, 2, getWidth() - x0));
                                int y = (getHeight() - image.getHeight())/2;
                                g.drawImage(image, x0, y, this);
                            } catch(Exception ignore) {}
                        }
                    };
                } else {
                    curfield = new JTextField(22);
                }
                fieldMap.put(fieldname,curfield);
                curfield.setText(account.getField(fieldname));
                Utils.setgrid(c,cury,1,GridBagConstraints.REMAINDER,1,GridBagConstraints.HORIZONTAL,GridBagConstraints.NORTHEAST,1);
                content.add(fieldMap.get(fieldname),c);
                cury++;
            }
        }

        Utils.setgrid(c,cury,0,1,1,GridBagConstraints.HORIZONTAL,GridBagConstraints.NORTHWEST,0.5);
            JButton btnaddfield = new JButton(lang.getString("ADDFIELD"));
            btnaddfield.addActionListener(new ActionListener() {
                public void actionPerformed(ActionEvent e) {
                    showAddFieldDialog("", false);
                }
            });
            btnaddfield.setHorizontalAlignment(SwingConstants.LEFT);
            try {
                ImageIcon icoName = new ImageIcon();
                URL URLicon = this.getClass().getResource("images/add_16.png");
                icoName.setImage(Toolkit.getDefaultToolkit().getImage(URLicon));
                btnaddfield.setIcon(icoName);
            } catch(Exception e) { }
            content.add(btnaddfield,c);
            //cury++;

//        Utils.setgrid(c,cury,0,1,1,GridBagConstraints.NONE,GridBagConstraints.NORTHWEST,0.5);
  //          content.add(Box.createHorizontalStrut(10), c);
    //        cury++;
            
        Utils.setgrid(c,cury,0,1,1,GridBagConstraints.HORIZONTAL,GridBagConstraints.NORTHWEST,0.5);
            Box pnlIcon = Box.createHorizontalBox();
            content.add(pnlIcon, c);
            JLabel lblIcon = new JLabel(lang.getString("ICON")+":");
                lblIcon.setLabelFor(iconTable);
                lblIcon.setBorder(null);
                pnlIcon.add(lblIcon);
            pnlIcon.add(Box.createHorizontalGlue());
            JButton btnMoreIcons = new JButton("");
                btnMoreIcons.addActionListener(new ActionListener() {
                    public void actionPerformed(ActionEvent e) {
                        JOptionPane.showMessageDialog(null, lang.getString("ICONSNEEDED"), lang.getString("ICON"), JOptionPane.INFORMATION_MESSAGE);
                    }
                });
                btnMoreIcons.setHorizontalAlignment(SwingConstants.LEFT);
                try {
                    ImageIcon icoName = new ImageIcon();
                    URL URLicon = this.getClass().getResource("images/bulb_16.png");
                    icoName.setImage(Toolkit.getDefaultToolkit().getImage(URLicon));
                    btnMoreIcons.setIcon(icoName);
                } catch(Exception e) { }
                pnlIcon.add(btnMoreIcons);
        Utils.setgrid(c,cury,1,GridBagConstraints.REMAINDER,1,GridBagConstraints.HORIZONTAL,GridBagConstraints.NORTHWEST,1);
            content.add(iconTable,c);
            iconTable.setBorder(BorderFactory.createLineBorder(Color.BLACK));
            if(!account.getName().equals("")) { // this is an edit, not a new account
                try {
                    int[] currentIconLoc = iconMap.get(account.getIcon());
                    iconTable.changeSelection(currentIconLoc[0], currentIconLoc[1], false, false);
                } catch(NullPointerException e) { // icon doesn't exist
                    try {
                        int[] defaultIconLoc = iconMap.get("default");
                        iconTable.changeSelection(defaultIconLoc[0], defaultIconLoc[1], false, false);
                    } catch(NullPointerException ignore) { /* default icon doesn't exist either */ }
                }
            } else {
                int[] defaultIconLoc = iconMap.get("default");
                iconTable.changeSelection(defaultIconLoc[0], defaultIconLoc[1], false, false);
            }
            cury++;
        if(account.getShowNotes()) {
            Utils.setgrid(c,cury,0,1,1,GridBagConstraints.HORIZONTAL,GridBagConstraints.NORTHWEST,0.5);
                JLabel lblNotes = new JLabel(lang.getString("NOTES")+":");
                content.add(lblNotes,c);
            Utils.setgrid(c,cury,1,GridBagConstraints.REMAINDER,1,GridBagConstraints.BOTH,GridBagConstraints.NORTHWEST,1);
                txtNotes = new JTextArea(account.getNotes(),4,15);
                txtNotes.setLineWrap(true);
                txtNotes.setWrapStyleWord(true);
                JScrollPane scrollNotes = new JScrollPane(txtNotes);
                scrollNotes.setMaximumSize(new Dimension(1000,1000));
                content.add(scrollNotes,c);
                cury++;
        }
        c.weighty = 1;
        Utils.setgrid(c,cury,1,GridBagConstraints.REMAINDER,1,GridBagConstraints.NONE,GridBagConstraints.NORTHWEST,1.5);
        content.add(Box.createVerticalGlue(), c);
        cury++;
        c.weighty = 0;
        
        Utils.setgrid(c,cury,0,3,1,GridBagConstraints.HORIZONTAL,GridBagConstraints.NORTHWEST,1.5);
            content.add(buttonBox,c);
        content.revalidate();
        this.validate();
        this.pack();
        double screenHeight = Toolkit.getDefaultToolkit().getScreenSize().getHeight() - 20;
        if(this.getHeight() > screenHeight) {
            this.setMaximumSize(new Dimension(750, (int)Math.round(screenHeight*0.85)));
            this.pack();
        }
        txtAccName.requestFocusInWindow();
        scrollContainer.getViewport().setViewPosition(new Point(0,0));
    }
    
    /**
    * Adds the list of icons from Constants.iconNames to a JTable (iconTable) 
    */
    private JTable iconBox() {
        try {
            int col=0, cols=8, numIcons = Constants.iconNames.length;
            iconMap = new HashMap<String,int[]>();
            IconTableModel iconTableModel = new IconTableModel(cols);
            Arrays.sort(Constants.iconNames);
            int i=0, j=0;
            rowloop: while(col<numIcons) {
 //System.out.println(c+" "+iconNames[c]+" - "+i+":"+j);
                iconTableModel.add(Constants.iconNames[col]);
                iconMap.put(Constants.iconNames[col], new int[] { i,j });
                if(j == cols-1) {
                    j=0;
                    i++;
                } else {
                    j++;
                }
                
                col++;
            }
            iconTableModel.complete();
            iconTable = new JTable(iconTableModel);
            iconTable.setTableHeader(null);
            iconTable.setShowGrid(false);
            iconTable.setRowHeight(38);
            iconTable.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
            iconTable.setCellSelectionEnabled(true);
            TableCellRenderer ImageRenderer = new Utils.IconRenderer();
            for(i=0;i<cols;i++) {
                TableColumn column = iconTable.getColumnModel().getColumn(i);
                column.setCellRenderer(ImageRenderer);
                column.setPreferredWidth(38);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return iconTable;
    }
    
    /**
     * Adds a field to the account currently being edited.
     * @param e The ActionEvent created by the Ok button on the showAddFieldDialog() form.
     * @param oldname The old name of the field.
     * @param newname The new name.
     */
    private void addField(String oldname, String newname, boolean editing) {
        if(editing) {
            account.getTypeObject().replaceField(oldname, newname);
        } else {
            account.getTypeObject().getFieldMap().put(newname, "");
        }
        getTextFields();
    }
    
    
    /**
     * Shows the 'Add Field' or 'Edit Field' dialog box. 
     * @param fieldName The name of the field to be renamed if editing a field name.
     *                  If blank, adds a new field.
     */
    private void showAddFieldDialog(String fieldName, boolean editing) {
        account.setName(txtAccName.getText());
        LinkedHashMap<String, String> fields = account.getTypeObject().getFieldMap();
        for(String fieldname : fields.keySet()) {
            account.setField(fieldname, ((JTextField)fieldMap.get(fieldname)).getText());
        }
        FrmAddField addFieldDialog = new FrmAddField(this, account, fieldName, editing, lang);
        if(addFieldDialog.getResult() == JOptionPane.OK_OPTION) {
            addField(fieldName, addFieldDialog.getFieldName(), editing);
        }
    }
    
    /**
     * Opens the 'Configure AutoType' dialog
     */
    private void configureAutoType() {
        if(System.getProperty("os.name").toLowerCase().startsWith("windows")) {
            boolean autoTypeConfigExists = hiddenMap.containsKey("~}!AutoType");
            FrmAutoType frmAutoType = null;
            ArrayList<String> fields = new ArrayList<String>();
            for(String fieldname : fieldMap.keySet()) {
                fields.add(fieldname);
            }
            if(autoTypeConfigExists) {
                frmAutoType = new FrmAutoType((ILanguageParent)thisDialog, hiddenMap.get("~}!AutoType"), fields);
            } else {
                frmAutoType = new FrmAutoType((ILanguageParent)thisDialog, fields);
            }
            if(frmAutoType.getResult() == JOptionPane.OK_OPTION) {
                hiddenMap.put("~}!AutoType", frmAutoType.getConfig());
            }
        } else {
            JOptionPane.showMessageDialog(this, "AutoType is only available for Windows.\nIf you'd like to add AutoType to another platform please email hjennerway@mi6.nu for more information.", lang.getString("ERROR"), JOptionPane.ERROR_MESSAGE);
        }
    }

    /**
    * Checks that this account has a name and does not already exist
    * @return True if the account is valid, otherwise False.
    */
    private boolean validateAccount() {
        String accName = txtAccName.getText().trim();
        if(accName.length() == 0) {
            txtAccName.requestFocusInWindow();
            JOptionPane.showMessageDialog(this,lang.getString("ERR_ACCOUNTBLANK"),lang.getString("ERR_ACCOUNTNAMEINVALID"), JOptionPane.ERROR_MESSAGE);
            return false;
        } else if(Utils.getTreeIndex(accName, accountTree) >= 0 && (!editing)) { // actionCommand is "add", and account exists
            txtAccName.selectAll();
            JOptionPane.showMessageDialog(this,lang.getString("ERR_ACCOUNTEXISTS"),lang.getString("ERR_ACCOUNTNAMEINVALID"), JOptionPane.ERROR_MESSAGE);
            return false;
        }
        return true;
    }
    
    /*============================ ILanguageParent ==========================*/
    /**
     * Returns the current langiage ResourceBundle
     * @return The current langiage ResourceBundle
     */
    public ResourceBundle getLanguage() {
        return owner.getLanguage();
    }
    
    public Component getParentWindow() {
        return thisDialog;
    }
    
    public boolean getDebug() {
        return owner.getDebug();
    }
    /*============================ End ILanguageParent ==========================*/
    
    /**
    * Gets the account being added/edited
    * @return The account being added/edited
    */
    public Account getAccount() {
        if(account == null) {
            return null;
        } else {
            String acctype = (String)cAccType.getSelectedItem();
            String accicon = iconTable.getValueAt(iconTable.getSelectedRow(), iconTable.getSelectedColumn()).toString();
            String accgroup = cAccGroup.getSelectedItem().toString();
            long acccreated = account.getCreated();
            LinkedHashMap<String, String> tempmap = new LinkedHashMap<String, String>();
            for(Object fieldnameobj : fieldMap.keySet()) {
                String fieldname = fieldnameobj.toString();
                JTextField box = fieldMap.get(fieldname);
                String val = box.getText();
                tempmap.put(fieldname, val);
            }
            for(Object fieldnameobj : hiddenMap.keySet()) {
                tempmap.put(fieldnameobj.toString(), hiddenMap.get(fieldnameobj.toString()));
            }
            boolean showNotes = account.getShowNotes();
            String notes = "";
            if(showNotes) {
                notes = txtNotes.getText();
            }
            String typeID = "";
            int idx = Utils.getTypeIndex(acctype, types, "visible");
            if(idx >=0) {
                typeID = types.get(idx).getID();
            } else if(tempType != null) {
                typeID = tempType.getID();
            }
            AccType info = new AccType(typeID, acctype, tempmap, showNotes, notes);
            account = new Account(txtAccName.getText(), acctype, accicon, info, true, accgroup, acccreated, new java.util.Date().getTime());
            return account;
        }
    }
    
    /**
    * Refreshes the text fields when the account type changes
    */
    class AccTypeChoiceListener implements ItemListener {
        // Fills the account specific fields when the value of JComboBox 'cacctype' changes
        public void itemStateChanged(ItemEvent e) {
            if(tempType != null && tempType.getName().equals(cAccType.getSelectedItem())) {
                account.setType(tempType);
            } else {
                account.setType(types.get(Utils.getTypeIndex((String)cAccType.getSelectedItem(), types, "types")));
            }
            getTextFields();
        }
    }
}
